using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using Microsoft.Security.Application;


namespace SecurityLinkUp
{
    public class UserData
    {
        public static User GetUser(Guid UserID)
        {
            try
            {
                MembershipUser usr = Membership.GetUser(UserID);

                if (usr == null)
                {
                    return null;
                }

                // do a query to see if the user has and profile info
                string connstr = Security.GetDBConnectionString();
                using (SqlConnection conn = new SqlConnection(connstr))
                {
                    conn.Open();
                    // setup the query to get all the (active) communities
                    SqlCommand cmd = new SqlCommand("GetUserInfo", conn);
                    cmd.Parameters.Add(new SqlParameter("@UserID", usr.ProviderUserKey.ToString()));
                    cmd.CommandType = CommandType.StoredProcedure;
                    SqlDataReader reader = cmd.ExecuteReader();
                    User u;
                    if (reader.HasRows)
                    {
                        reader.Read();
                        u = UserData.CreateUserFromDBRecord(reader);
                    }
                    else
                    {
                        u = new User((Guid)usr.ProviderUserKey,
                                    usr.UserName,
                                    usr.Email,
                                    null, null, null, null, false);
                    }
                    return u;
                }
            }
            catch (Exception ex)
            {
                Log.LogException(ex);
                return null;
            }

        }

        public static SortedList GetAllUsers()
        {
            SortedList ret = new SortedList();
                       
            try
            {
                MembershipUserCollection members = Membership.GetAllUsers();
                foreach(MembershipUser usr in members)
                {
                    // do a query to see if the user has and profile info   
                    string connstr = Security.GetDBConnectionString();
                    using (SqlConnection conn = new SqlConnection(connstr))
                    {
                        conn.Open();
                        // setup the query to get all the (active) communities
                        SqlCommand cmd = new SqlCommand("GetUserInfo", conn);
                        cmd.Parameters.Add(new SqlParameter("@UserID", usr.ProviderUserKey.ToString()));
                        cmd.CommandType = CommandType.StoredProcedure;
                        SqlDataReader reader = cmd.ExecuteReader();
                        User u;
                        if (reader.HasRows)
                        {
                            reader.Read();
                            u = UserData.CreateUserFromDBRecord(reader);
                        }
                        else
                        {
                            u = new User((Guid)usr.ProviderUserKey,
                                        usr.UserName,
                                        usr.Email,
                                        null, null, null, null, false);
                        }

                        ret.Add(u.uid, u);
                    }
                }

                return ret;
            }
            catch (Exception ex)
            {
                Log.LogException(ex);
                return null;
            }
        }




        #region Get/Save chapter object from/to database
        // TODO: we could probably do with limiting the scope of these functions so that
        // they cant be called directly, and you have to go through the main operation
        // functions above.  However, because we are calling these functions static, we can't
        // move them from "public"?

        // Creates a user object from a database record
        public static User CreateUserFromDBRecord(SqlDataReader data)
        {
            //create a user object
            try
            {
                // get the asp.net membership info first
                Guid userid = new Guid(data["userid"].ToString());
                MembershipUser usr = Membership.GetUser(userid);
                if (usr == null)
                {
                    // can't find the user - bail out
                    return null;
                }

                

                // grab the info from the DB
                if ((data["geolat"] == DBNull.Value) || (data["geolong"] == DBNull.Value))
                {
                    // create user using the "no position" method
                    User u = new User(userid,
                                    usr.UserName,
                                    usr.Email,
                                    data["realname"].ToString(),
                                    data["picfile"].ToString(),
                                    data["companyname"].ToString(),
                                    data["jobtitle"].ToString(),
                                    bool.Parse(data["allowemail"].ToString())
                                    );
                    return u;
                }
                else
                {
                    // create a user with position
                    User u = new User(userid,
                                    usr.UserName,
                                    usr.Email,
                                    data["realname"].ToString(),
                                    data["picfile"].ToString(),
                                    data["companyname"].ToString(),
                                    data["jobtitle"].ToString(),
                                    bool.Parse(data["allowemail"].ToString())
                                    );
                    u.SetGeoData(data["geoarea"].ToString(),
                                 double.Parse(data["geolat"].ToString()),
                                 double.Parse(data["geolong"].ToString())
                                );
                    return u;
                }

            }
            catch (Exception ex)
            {
                Log.LogException(ex);
                return null;
            }
        }

        // saves a user object to the database
        public static string SaveUserToDB(User u)
        {
            string connstr = Security.GetDBConnectionString();
            using (SqlConnection conn = new SqlConnection(connstr))
            {
                try
                {
                    conn.Open();

                    // get the asp.net membership info first
                    MembershipUser usr = Membership.GetUser(u.uid);
                    if (usr == null)
                    {
                        // can't find the user - bail out
                        return "Could not find user";
                    }

                    // set the info held in the asp.net membership store
                    usr.Email = u.email;

                    // save the user info
                    SqlCommand cmd = new SqlCommand("SaveUserInfo", conn);
                    cmd.Parameters.Add(new SqlParameter("@ID", u.uid.ToString()));
                    cmd.Parameters.Add(new SqlParameter("@name", u.name));
                    cmd.Parameters.Add(new SqlParameter("@picfile", u.picfile));
                    cmd.Parameters.Add(new SqlParameter("@companyname", u.company));
                    cmd.Parameters.Add(new SqlParameter("@jobtitle", u.jobtitle));
                    cmd.Parameters.Add(new SqlParameter("@allowemail", u.AllowEmail));
                    if (u.HasPosition)
                    {
                        cmd.Parameters.Add(new SqlParameter("@geoarea", u.geoarea));
                        cmd.Parameters.Add(new SqlParameter("@geolat", u.geolat));
                        cmd.Parameters.Add(new SqlParameter("@geolong", u.geolong));
                    }
                    else
                    {
                        cmd.Parameters.Add(new SqlParameter("@geoarea", DBNull.Value));
                        cmd.Parameters.Add(new SqlParameter("@geolat", DBNull.Value));
                        cmd.Parameters.Add(new SqlParameter("@geolong", DBNull.Value));
                    }
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.ExecuteNonQuery();
                    return "Saved";
                }
                catch (Exception ex)
                {
                    Log.LogException(ex);
                    return "Error saving";
                }
            }
        }

        #endregion

    }

    public class User
    {
        private Guid m_uid;
        private string m_username;
        private string m_email;
        private string m_name;
        private string m_company;
        private string m_jobtitle;
        private string m_picfile;
        private string m_geoarea;
        private double m_geolat;
        private double m_geolong;
        private bool m_hasposition;
        private bool m_allowemail;

        private const string defaultpicurl = "/Images/nouserimage.gif";

        // constructor version with no geo position
        public User(Guid uid, string username, string email, string name, string picfile, string company, string jobtitle, bool allowemail)
        {
            m_uid = uid;
            m_username = username;
            m_name = name;
            m_email = email;
            if ((picfile != null) && (picfile != ""))
            {
                m_picfile = picfile;
            }
            else
            {
                m_picfile = defaultpicurl;
            }
            m_company = company;
            m_jobtitle = jobtitle;
            m_hasposition = false;
            m_allowemail = allowemail;
        }

        public void SetGeoData(string GeoArea, double GeoLat, double GeoLong)
        {
            m_geoarea = GeoArea;
            m_geolat = GeoLat;
            m_geolong = GeoLong;
            m_hasposition = true;
        }

        public string SavePicture(HttpPostedFile uploadfile)
        {
            string userimagesdir = ConfigurationManager.AppSettings["UserImagesDir"];

            try
            {
                // check the file size
                // BUGBUG: Actually, this would be really nice to do, and give a graceful error
                // but it's impossible to catch here, as IIS handles it first.  See
                // http://forums.asp.net/p/1076458/1582377.aspx for a discussion

                // check that it's a file we'll accept
                string filetypes = ConfigurationManager.AppSettings["UserImagesFileTypes"];
                string[] typesarray = filetypes.Split('|');
                if (!InStringArray(typesarray, uploadfile.ContentType))
                {
                    return "The file was not one of the permitted types";
                }

                // want to restrict the max size to 150x150
                Bitmap bitmap = new Bitmap(uploadfile.InputStream, false);
                if ((bitmap.Width > 150) || (bitmap.Height > 150))
                {
                    return "The file is bigger than 150x150 pixels";
                }

                // save the file
                string ext = System.IO.Path.GetExtension(uploadfile.FileName);
                if (ext == null)
                {
                    return "No file extention was provided";
                }
                uploadfile.SaveAs(userimagesdir + m_uid + ext);

                // update the db
                m_picfile = userimagesdir + m_uid + ext;
                string Error = UserData.SaveUserToDB(this);

                // return the message
                return Error;

            }
            catch (Exception ex)
            {
                Log.LogException(ex);
                return "Error saving";
            }
        }

        private bool InStringArray(string[] ar, string str)
        {
            // look for match of str in ar
            for (int i = 0; i < ar.Length; i++)
            {
                if (ar[i] == str)
                {
                    return true;
                }
            }

            return false;
        }


        public Guid uid
        {
            get { return m_uid; }
        }

        public string username
        {
            get { return AntiXss.HtmlEncode(m_username); }
        }

        public string email
        {
            get { return AntiXss.HtmlEncode(m_email); }
            set { m_email = value; }
        }

        public string name
        {
            get
            {
                if (IsRealName)
                {
                    return AntiXss.HtmlEncode(m_name);
                }
                else
                {
                    return AntiXss.HtmlEncode(m_username);
                }
            }
            set { m_name = value; }
        }

        public bool IsRealName
        {
            get
            {
                // if we have a name for this user use it, otherwise use
                // the username
                if ((m_name != null) && (m_name != ""))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public string company
        {
            get { return AntiXss.HtmlEncode(m_company); }
            set { m_company = value; }
        }

        public string jobtitle
        {
            get { return AntiXss.HtmlEncode(m_jobtitle); }
            set { m_jobtitle = value; }
        }

        public string picfile
        {
            get { return m_picfile; }
        }

        public string picurl
        {
            get
            {
                // start off with the "on-file" location of the presentation
                string url = m_picfile;

                // see if the file actually exists
                if (File.Exists(url))
                {
                    // remove the directory location, to just give us the file
                    url = url.Replace(ConfigurationManager.AppSettings["UserImagesDir"], "");

                    // add the site url and presentation prefix to form the url
                    url = ConfigurationManager.AppSettings["SiteURL"] + ConfigurationManager.AppSettings["UserImagesURLPrefix"] + url;

                    // return the fixed-up url
                    return url;
                }
                else
                {
                    // just return the default image
                    return defaultpicurl;
                }

            }
        }


        public string geoarea
        {
            get { return m_geoarea; }
        }

        public double geolat
        {
            get { return m_geolat; }
        }

        public double geolong
        {
            get { return m_geolong; }
        }

        public bool HasPosition
        {
            get { return m_hasposition; }
        }

        public bool AllowEmail
        {
            get { return m_allowemail; }
            set { m_allowemail = value; }
        }
    }
}
